﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Objects.DataClasses;
using System.Xml;

using FRL.DebtChased.Extensions;
using FRL.DebtChased.WebServices;

namespace FRL.DebtChased.Repository
{

	/// <summary>
	/// Extensions to the Workflow model
	/// </summary>
	public partial class Workflow
	{

		/////////////////////////////////////////////////////////////
		// Static Operations

		public static string GetName( DebtChasedEntities ent, int iWorkflowId )
		{

			// Lookup the name in the table
			return (from w in ent.Workflows
							 where (w.WorkflowId == iWorkflowId)
							 select w.Name).FirstOrDefault();

		}

		public static WorkflowTransportWrapper GetWorkflowTransportWrapper(DebtChasedEntities ent, int iWorkflowId)
		{

			// Declare return variable
			WorkflowTransportWrapper Ftmp = new WorkflowTransportWrapper();
			Ftmp.WorkflowId = iWorkflowId;

			// Load the workflow details
			var result = (from wt in ent.Workflows
						  join ais in ent.AccountInvoiceStatus on wt.AccountInvoiceStatusId equals ais.AccountInvoiceStatusId
						  where wt.WorkflowId == iWorkflowId
						  select new { xml = wt.Xml, statusId = wt.AccountInvoiceStatusId, isInstalmentPlanStatus = ais.IsInstalmentPlanStatus }).FirstOrDefault();

			// Update function parameters
			Ftmp.AccountInvoiceStatusId = result.statusId;
			Ftmp.IsInstalmentPlanStatus = result.isInstalmentPlanStatus;

			// Update return variable
			Ftmp.Buffer = Encoding.Unicode.GetBytes(result.xml);

			// Return variable
			return Ftmp;

		}

		public static FRL.DebtChased.WorkflowObjects.Workflow GetWorkflow( DebtChasedEntities ent, int iWorkflowId )
		{

			// Declare return variable
			FRL.DebtChased.WorkflowObjects.Workflow Ftmp = null;

			// Load the xml
			string strXml = (from wt in ent.Workflows
							 where wt.WorkflowId == iWorkflowId
							 select wt.Xml).FirstOrDefault();

			// Convert to a buffer
			byte[] buffer = Encoding.Unicode.GetBytes(strXml);

			// Unwrap buffer
			Ftmp = FRL.DebtChased.WorkflowObjects.Workflow.XmlFactory(buffer);

			// Return variable
			return Ftmp;

		}

		public static string SetXml( 
			DebtChasedEntities ent, 
			ref int iWorkflowId, 
			byte[] buffer, 
			int iAccountInvoiceStatusId, 
			int iUserId 
		)
		{

			// Declare return variable
			string strError = null;

			try
			{

				// Pull out the details
				FRL.DebtChased.WorkflowObjects.Workflow wf = FRL.DebtChased.WorkflowObjects.Workflow.XmlFactory(buffer);

				// Get the xml as a string
				string strXml = Encoding.Unicode.GetString(buffer);

				// Get the comm templates and popups used
				List<int> iCommBodiesUsed = new List<int>();
				List<int> iPopupsUsed = new List<int>();
				List<int> iLetterTypesUsed = new List<int>();
				wf.GetObjectsUsed(iCommBodiesUsed, iPopupsUsed, iLetterTypesUsed);

				// Get the summary
				string strSummary = wf.GetSummary(WorkflowObjects.Workflow.eSummaryFormat.Audit);

				// If editing a record...
				Workflow record = null;
				if (iWorkflowId != 0)
				{

					// Update the database record
					int iTemp = iWorkflowId;
					record = ent.Workflows.FirstOrDefault(wt => wt.WorkflowId == iTemp);
					record.Name = wf.Name;
					record.Summary = strSummary;
					record.Xml = strXml;

				}
				else
				{

					// Add a new workflow template
					record = Workflow.CreateWorkflow(0, wf.Name, strXml, true, iAccountInvoiceStatusId);
					record.Summary = strSummary;
					ent.Workflows.AddObject(record);

				}

				// Track changes
				UserAction.Session session = new UserAction.Session( iUserId, record, wf.Name );
				session.Summary = wf.GetSummary(WorkflowObjects.Workflow.eSummaryFormat.Audit);

				// Update comm body list
				List<int> iCurrent = (from wcb in record.WorkflowCommBodies select wcb.CommBodyId).ToList();
				List<int> toRemove = iCurrent.Minus(iCommBodiesUsed);
				foreach (int iRemoveId in toRemove)
				{
					WorkflowCommBody wcb = record.WorkflowCommBodies.First(wcb2 => wcb2.CommBodyId == iRemoveId);
					ent.WorkflowCommBodies.DeleteObject(wcb);
				}
				List<int> toAdd = iCommBodiesUsed.Minus(iCurrent);
				foreach (int iCommBodyId in toAdd)
				{
					WorkflowCommBody newWcb = WorkflowCommBody.CreateWorkflowCommBody(0, 0, iCommBodyId);
					newWcb.Workflow = record;
					record.WorkflowCommBodies.Add(newWcb);
				}

				// Update popups
				iCurrent = (from wp in record.WorkflowPopups select wp.PopupId).ToList();
				toRemove = iCurrent.Minus(iPopupsUsed);
				foreach (int iRemoveId in toRemove)
				{
					WorkflowPopup wp = record.WorkflowPopups.First(wp2 => wp2.PopupId == iRemoveId);
					ent.WorkflowPopups.DeleteObject(wp);
				}
				toAdd = iPopupsUsed.Minus(iCurrent);
				foreach (int iPopupsId in toAdd)
				{
					WorkflowPopup newWp = WorkflowPopup.CreateWorkflowPopup(0, 0, iPopupsId);
					newWp.Workflow = record;
					record.WorkflowPopups.Add(newWp);
				}

				// Update letter-types
				iCurrent = (from wp in record.WorkflowLetterTypes select wp.LetterTypeId).ToList();
				toRemove = iCurrent.Minus(iLetterTypesUsed);
				foreach (int iRemoveId in toRemove)
				{
					WorkflowLetterType wlt = record.WorkflowLetterTypes.First(wlt2 => wlt2.LetterTypeId == iRemoveId);
					ent.WorkflowLetterTypes.DeleteObject(wlt);
				}
				toAdd = iLetterTypesUsed.Minus(iCurrent);
				foreach (int iLetterTypeId in toAdd)
				{
					WorkflowLetterType newWlt = WorkflowLetterType.CreateWorkflowLetterType(0, 0, iLetterTypeId);
					newWlt.Workflow = record;
					record.WorkflowLetterTypes.Add(newWlt);
				}

				// Update the repository
				ent.SaveChanges();

				// Get the workflow id
				iWorkflowId = record.WorkflowId;

				// Save the user activity
				session.SaveChanges(ent);

			}
			catch (Exception x)
			{

				// Process error
				strError = ErrorProcessing.HandleException(x, "save workflow", iUserId);

			}

			// Return variable
			return strError;

		}

		public static WorkflowsTransportWrapper GetTransportWrapper(DebtChasedEntities ent, int iClientId)
		{

			// Declare return variable
			WorkflowsTransportWrapper Ftmp = new WorkflowsTransportWrapper();
			Ftmp.AccountInvoiceStatusList = new List<AccountInvoiceStatusTransport>();
			Ftmp.WorkflowList = new List<WorkflowSummaryTransport>();

			// Set the client id and name
			Ftmp.ClientId = iClientId;
			if (iClientId != 0)
				Ftmp.ClientName = (from c in ent.Clients where (c.ClientId == iClientId) select c.Name).FirstOrDefault();

			// Load the invoice status list
			var results = ent.AccountInvoiceStatusProc(iClientId);
			foreach (var result in results)
			{

				// Load the status
				AccountInvoiceStatusTransport invoiceStatus = new AccountInvoiceStatusTransport();
				invoiceStatus.AccountInvoiceStatusId = result.fdAccountInvoiceStatusId;
				invoiceStatus.DefaultWorkflowId = result.fdDefaultWorkflowId ?? 0;
				invoiceStatus.ClientWorkflowId = result.fdClientWorkflowId ?? 0;
				invoiceStatus.HasGlobalScope = result.fdIsGlobalScope;
				invoiceStatus.InUse = (result.fdInvoiceCount > 0);
				invoiceStatus.InvoiceStatusName = result.fdName;
				invoiceStatus.IsInstalmentPlanStatus = result.fdIsInstalmentPlanStatus;
				Ftmp.AccountInvoiceStatusList.Add(invoiceStatus); 

			}

			// Load the workflow list
			var workflows = from w in ent.Workflows.Include("newWorkflowSuperceeds").Include("AccountInvoiceStatusWorkflows")
							select new {
								w.WorkflowId,
								w.Name,
								w.Summary,
								w.AccountInvoiceStatusId,
								IsSuperceeded = (w.NewWorkflowSuperceeds.Count > 0),
								UsageCount = w.AccountInvoiceStatusWorkflows.Count
							};
			foreach (var wf in workflows)
			{

				// Load the workflow
				WorkflowSummaryTransport wfTransport = new WorkflowSummaryTransport();
				wfTransport.WorkflowId = wf.WorkflowId;
				wfTransport.WorkflowName = wf.Name;
				wfTransport.InvoiceStatusId = wf.AccountInvoiceStatusId;
				wfTransport.Summary = wf.Summary;
				wfTransport.UsageCount = wf.UsageCount;
				wfTransport.IsSuperceeded = wf.IsSuperceeded;
				Ftmp.WorkflowList.Add(wfTransport);

			}

			// Return variable
			return Ftmp;

		}

		public static string Delete(DebtChasedEntities ent, int iWorkflowId, int iUserId)
		{

			// Declare return variable
			string strError = null;

			try
			{

				// Load the workflow
				Workflow wf = ent.Workflows.FirstOrDefault(w => w.WorkflowId == iWorkflowId);

				// Delete workflow
				ent.Workflows.DeleteObject(wf);

				// Delete the popup references
				var popups = from wp in ent.WorkflowPopups
							 where (wp.WorkflowId == iWorkflowId)
							 select wp;
				foreach (WorkflowPopup wp in popups)
					ent.WorkflowPopups.DeleteObject(wp);

				// Delete the comm-body references
				var commBodies = from wcb in ent.WorkflowCommBodies
									where (wcb.WorkflowId == iWorkflowId)
									select wcb;
				foreach (WorkflowCommBody wcb in commBodies)
					ent.WorkflowCommBodies.DeleteObject(wcb);

				// Save changes
				ent.SaveChanges();

			}
			catch (Exception x)
			{

				// Process error
				strError = ErrorProcessing.HandleException(x,"delete workflow",iUserId);

			}

			// Return variable
			return strError;

		}

		public static Dictionary<int, string> GetDictionary(DebtChasedEntities ent, bool bAddNoneOption, string strNone)
		{

			// Declare return variable
			Dictionary<int, string> Ftmp = new Dictionary<int,string>();
			if(bAddNoneOption)
				Ftmp.Add(0, strNone);

			// Load dictionary from entities
			var results = from wf in ent.Workflows
						  orderby wf.Name
						  select new { wf.WorkflowId, wf.Name };

			// Add to dictionary
			foreach(var ob in results)
				Ftmp.Add( ob.WorkflowId, ob.Name );

			// Return variable
			return Ftmp;

		}

	}

}
